package frame.options.simulation.results;

import java.awt.BorderLayout;
import java.awt.Frame;
import java.util.ArrayList;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import model.algorithms.linksMapping.LinksMappingAlgorithm;
import model.components.networks.sdn.SdnNetwork;
import model.components.networks.virtual.VirtualNetwork;
import frame.options.simulation.Simulation;
import frame.options.simulation.results.sdn.graphical.SdnNetworkViewersPanel;
import frame.options.simulation.results.sdn.numerical.SdnNetworkTablesPanel;
import frame.options.simulation.results.sdn.summary.SdnNetworksTable;
import frame.options.simulation.results.virtual.graphical.VirtualNetworkViewersPanel;
import frame.options.simulation.results.virtual.numerical.VirtualNetworkTablesPanel;
import frame.options.simulation.results.virtual.summary.VirtualNetworksTable;

@SuppressWarnings("serial")
public class ResultsFrame extends JFrame implements ChangeListener
{
	private Simulation simulation;
	public Simulation getSimulation(){ return simulation; }
	public void setSimulation( Simulation simulation ){ this.simulation = simulation; }
	
	private JTabbedPane sdnNetworksTabbedPane;
	public JTabbedPane getSdnNetworksTabbedPane(){ return sdnNetworksTabbedPane; }
	public void setSdnNetworksTabbedPane( JTabbedPane sdnNetworksTabbedPane ){ this.sdnNetworksTabbedPane = sdnNetworksTabbedPane; }
	
	private JTabbedPane virtualNetworksTabbedPane;
	public JTabbedPane getVirtualNetworksTabbedPane(){ return virtualNetworksTabbedPane; }
	public void setVirtualNetworksTabbedPane( JTabbedPane virtualNetworksTabbedPane ){ this.virtualNetworksTabbedPane = virtualNetworksTabbedPane; }
	
	private List< SdnNetworkViewersPanel > sdnNetworksViewersPanels;
	public List< SdnNetworkViewersPanel > getSdnNetworksViewersPanels(){ return sdnNetworksViewersPanels; }
	public void setSdnNetworksViewersPanels( List< SdnNetworkViewersPanel > sdnNetworksViewersPanels ){ this.sdnNetworksViewersPanels = sdnNetworksViewersPanels; }
	
	private List< VirtualNetworkViewersPanel > virtualNetworksViewersPanels;
	public List< VirtualNetworkViewersPanel > getVirtualNetworksViewersPanels(){ return virtualNetworksViewersPanels; }
	public void setVirtualNetworksViewersPanels( List< VirtualNetworkViewersPanel > virtualNetworksViewersPanels ){ this.virtualNetworksViewersPanels = virtualNetworksViewersPanels; }
	
	private JTabbedPane sdnNetworksViewersPanelsTabbedPane;
	public JTabbedPane getSdnNetworksViewersPanelsTabbedPane(){ return sdnNetworksViewersPanelsTabbedPane; }
	public void setSdnNetworksViewersPanelsTabbedPane( JTabbedPane sdnNetworksViewersPanelsTabbedPane ){ this.sdnNetworksViewersPanelsTabbedPane = sdnNetworksViewersPanelsTabbedPane; }

	private JTabbedPane virtualNetworksViewersPanelsTabbedPane;
	public JTabbedPane getVirtualNetworksViewersPanelsTabbedPane(){ return virtualNetworksViewersPanelsTabbedPane; }
	public void setVirtualNetworksViewersPanelsTabbedPane( JTabbedPane virtualNetworksViewersPanelsTabbedPane ){ this.virtualNetworksViewersPanelsTabbedPane = virtualNetworksViewersPanelsTabbedPane; }
	
	private List< SdnNetworkTablesPanel > sdnNetworksTablesPanels;
	public List< SdnNetworkTablesPanel > getSdnNetworksTablesPanels(){ return sdnNetworksTablesPanels; }
	public void setSdnNetworksTablesPanels( List< SdnNetworkTablesPanel > sdnNetworksTablesPanels ){ this.sdnNetworksTablesPanels = sdnNetworksTablesPanels; }

	private List< VirtualNetworkTablesPanel > virtualNetworksTablesPanels;
	public List< VirtualNetworkTablesPanel > getVirtualNetworksTablesPanels(){ return virtualNetworksTablesPanels; }
	public void setVirtualNetworksTablesPanels( List< VirtualNetworkTablesPanel > virtualNetworksTablesPanels ){ this.virtualNetworksTablesPanels = virtualNetworksTablesPanels; }
	
	private JTabbedPane sdnNetworksTablesPanelsTabbedPane;
	public JTabbedPane getSdnNetworksTablesPanelsTabbedPane(){ return sdnNetworksTablesPanelsTabbedPane; }
	public void setSdnNetworksTablesPanelsTabbedPane( JTabbedPane sdnNetworksTablesPanelsTabbedPane ){ this.sdnNetworksTablesPanelsTabbedPane = sdnNetworksTablesPanelsTabbedPane; }

	private JTabbedPane virtualNetworksTablesPanelsTabbedPane;
	public JTabbedPane getVirtualNetworksTablesPanelsTabbedPane(){ return virtualNetworksTablesPanelsTabbedPane; }
	public void setVirtualNetworksTablesPanelsTabbedPane( JTabbedPane virtualNetworksTablesPanelsTabbedPane ){ this.virtualNetworksTablesPanelsTabbedPane = virtualNetworksTablesPanelsTabbedPane; }

	private JPanel sdnNetworksTablePanel;
	public JPanel getSdnNetworksTablePanel(){ return sdnNetworksTablePanel; }
	public void setSdnNetworksTablePanel( JPanel sdnNetworksTablePanel ){ this.sdnNetworksTablePanel = sdnNetworksTablePanel; }

	private JPanel virtualNetworksTablePanel;
	public JPanel getVirtualNetworksTablePanel(){ return virtualNetworksTablePanel; }
	public void setVirtualNetworksTablePanel( JPanel virtualNetworksTablePanel ){ this.virtualNetworksTablePanel = virtualNetworksTablePanel; }
	
	public ResultsFrame( List< SdnNetwork > resultSdnNetworks, int simulatorSdnNetworksNumber, List< VirtualNetwork > resultVirtualNetworks, int simulatorVirtualNetworksNumber, Simulation simulation )
	{
		this.setSimulation( simulation );
		this.setSdnNetworksTabbedPane( this.physicalNetworksTabbedPane( resultSdnNetworks, simulatorSdnNetworksNumber ) );
		this.setVirtualNetworksTabbedPane( this.virtualNetworksTabbedPane( resultVirtualNetworks, simulatorVirtualNetworksNumber ) );
		
		JSplitPane networksSplitPane = new JSplitPane();
		networksSplitPane.setLeftComponent( this.getSdnNetworksTabbedPane() );
		networksSplitPane.setRightComponent( this.getVirtualNetworksTabbedPane() );
		
		this.setLayout( new BorderLayout() );
		this.add( this.simulationDataPanel(), BorderLayout.NORTH );
		this.add( networksSplitPane, BorderLayout.CENTER );
		this.setTitle( "Simulation results" );
		this.setIconImage( ( new ImageIcon( this.getClass().getResource( "/icons/upcSmall.png" ) ) ).getImage() );
		this.setAlwaysOnTop( false );
		this.setExtendedState( Frame.MAXIMIZED_BOTH );
	}
	private JPanel simulationDataPanel()
	{
		String text = null;
		
		text = "<html><b>SDN NETWORKS:</b> ";
		
		int i = 0;
		
		for( SdnNetwork sdnNetwork: this.getSimulation().getSdnNetworks() )
		{
			i++;
			
			if( i == this.getSimulation().getSdnNetworks().size() - 1 )
				text += sdnNetwork.getName() + " and ";
			
			else if( i < this.getSimulation().getSdnNetworks().size() - 1 )
				text += sdnNetwork.getName() + ", ";
			
			else
				text += sdnNetwork.getName();
		}
		
		text += "<br><b>VIRTUAL NETWORKS:</b> ";
		
		i = 0;
		
		for( VirtualNetwork virtualNetwork: this.getSimulation().getVirtualNetworks() )
		{
			i++;
			
			if( i == this.getSimulation().getVirtualNetworks().size() - 1 )
				text += virtualNetwork.getName() + " and ";
			
			else if( i < this.getSimulation().getVirtualNetworks().size() - 1 )
				text += virtualNetwork.getName() + ", ";
			
			else
				text += virtualNetwork.getName();
		}
		
		text += "<b> WITH BACKUP:</b> ";
		
		if( this.getSimulation().getLinksMappingAlgorithm().isBackupVirtualNetwork() )
			text += "Yes";
		else
			text += "No";
		
		text += "<br><b>VIRTUAL NETWORK SPLITTING ALGORITHM:</b> " + this.getSimulation().getSplittingAlgorithm().getName();
		
		text += "<br><b>WITH COORDINATED VIRTUAL NODE AND LINK MAPPING:</b> ";
		
		if( this.getSimulation().getEmbeddingAlgorithm() == null )
		{
			text += "No";
			text += " <b>VIRTUAL NODE MAPPING ALGORITHM:</b> " + this.getSimulation().getNodesMappingAlgorithm().getName();
		}
		else
		{
			text += "Yes";
			text += " <b>VIRTUAL NETWORK EMBEDDING ALGORITHM:</b> " + this.getSimulation().getEmbeddingAlgorithm().getName();
			text += " <b>ROUNDED VIRTUAL NODE MAPPING ALGORITHM:</b> " + this.getSimulation().getRoundingAlgorithm().getName();
		}
		
		text += "<br><b>VIRTUAL LINK MAPPING ALGORITHM:</b> " + this.getSimulation().getLinksMappingAlgorithm().getName();
		text += " <b>COST METRIC:</b> ";
		
		if( this.getSimulation().getLinksMappingAlgorithm().getCostMetric().equals( LinksMappingAlgorithm.DISTANCE_COST ) )
			text += "Distance</html>";
		
		else if( this.getSimulation().getLinksMappingAlgorithm().getCostMetric().equals( LinksMappingAlgorithm.BW_COST ) )
			text += "Bandwidth</html>";
		
		JPanel simulationDataPanel = new JPanel();
		simulationDataPanel.add( new JLabel( text ) );
		
		return simulationDataPanel;
	}
	
	private JTabbedPane physicalNetworksTabbedPane( List< SdnNetwork > resultPhysicalNetworks, int simulatorPhysicalNetworksNumber )
	{
		List< List< SdnNetwork > > physicalNetworksNetworks = new ArrayList< List< SdnNetwork > >();
		
		for( int i = 0; i < simulatorPhysicalNetworksNumber; i++ )
			physicalNetworksNetworks.add( new ArrayList< SdnNetwork >() );
		
		for( SdnNetwork physicalNetwork: resultPhysicalNetworks )
			physicalNetworksNetworks.get( physicalNetwork.getNumber() ).add( physicalNetwork );
		
		this.setSdnNetworksViewersPanelsTabbedPane( this.physicalNetworksVisualizationViewersPanelsTabbedPane( physicalNetworksNetworks ) );
		this.setSdnNetworksTablesPanelsTabbedPane( this.physicalNetworksTablesPanelsTabbedPane( physicalNetworksNetworks ) );
		this.setSdnNetworksTablePanel( this.physicalNetworksTablePanel( physicalNetworksNetworks ) );
		
		JTabbedPane physicalNetworksTabbedPane = new JTabbedPane();
		physicalNetworksTabbedPane.setName( "physicalNetworksTabbedPane" );
		physicalNetworksTabbedPane.setTabPlacement( SwingConstants.TOP );
		physicalNetworksTabbedPane.addTab( "Graphical", null, this.getSdnNetworksViewersPanelsTabbedPane(), "Graphical results of physical networks" );
		physicalNetworksTabbedPane.addTab( "Numerical", null, this.getSdnNetworksTablesPanelsTabbedPane(), "Numerical results of physical networks" );
		physicalNetworksTabbedPane.addTab( "Summary", null, this.getSdnNetworksTablePanel(), "Summary results of physical networks" );
		physicalNetworksTabbedPane.addChangeListener( this );
		
		return physicalNetworksTabbedPane;
	}
	private JTabbedPane physicalNetworksVisualizationViewersPanelsTabbedPane( List< List< SdnNetwork > > physicalNetworksNetworks )
	{
		this.setSdnNetworksViewersPanels( new ArrayList< SdnNetworkViewersPanel >() );
		
		JTabbedPane physicalNetworksVisualizationViewersPanelsTabbedPane = new JTabbedPane();
		
		for( int i = 0; i < physicalNetworksNetworks.size(); i++ )
		{
			String physicalNetworkName = physicalNetworksNetworks.get( i ).get( 0 ).getName();
			List< SdnNetwork > physicalNetworkNetworks = physicalNetworksNetworks.get( i );
			SdnNetworkViewersPanel sdnNetworkVisualizationViewersPanel = new SdnNetworkViewersPanel( physicalNetworkNetworks, this );
			physicalNetworksVisualizationViewersPanelsTabbedPane.addTab( physicalNetworkName, null, sdnNetworkVisualizationViewersPanel, null );
			
			this.getSdnNetworksViewersPanels().add( sdnNetworkVisualizationViewersPanel );
		}
		
		return physicalNetworksVisualizationViewersPanelsTabbedPane;
	}
	private JTabbedPane physicalNetworksTablesPanelsTabbedPane( List< List< SdnNetwork > > physicalNetworksNetworks )
	{
		JTabbedPane physicalNetworksTablesPanelsTabbedPane = new JTabbedPane();
		
		this.setSdnNetworksTablesPanels( new ArrayList< SdnNetworkTablesPanel >() );
		
		for( int i = 0; i < physicalNetworksNetworks.size(); i++ )
		{
			List< SdnNetwork > physicalNetworkNetworks = physicalNetworksNetworks.get( i );
			
			String physicalNetworkName = physicalNetworkNetworks.get( 0 ).getName();
			SdnNetworkTablesPanel sdnNetworkTablesPanel = new SdnNetworkTablesPanel( physicalNetworkNetworks, this );
			physicalNetworksTablesPanelsTabbedPane.addTab( physicalNetworkName, null, sdnNetworkTablesPanel, null );
			
			this.getSdnNetworksTablesPanels().add( sdnNetworkTablesPanel );
		}
		
		return physicalNetworksTablesPanelsTabbedPane;
	}
	private JPanel physicalNetworksTablePanel( List< List< SdnNetwork > > physicalNetworksNetworks )
	{
		JPanel panel = new JPanel();
		panel.add( new JScrollPane( new SdnNetworksTable( physicalNetworksNetworks ) ) );
		
		return panel;
	}
	
	private JTabbedPane virtualNetworksTabbedPane( List< VirtualNetwork > resultVirtualNetworks, int simulatorVirtualNetworksNumber )
	{
		List< List< VirtualNetwork > > virtualNetworksNetworks = new ArrayList< List< VirtualNetwork > >();
		
		for( int i = 0; i < simulatorVirtualNetworksNumber; i++ )
			virtualNetworksNetworks.add( new ArrayList< VirtualNetwork >() );
		
		for( VirtualNetwork resultVirtualNetwork: resultVirtualNetworks )
			virtualNetworksNetworks.get( resultVirtualNetwork.getNumber() ).add( resultVirtualNetwork );
		
		this.setVirtualNetworksViewersPanelsTabbedPane( this.virtualNetworksVisualizationViewersPanelsTabbedPane( virtualNetworksNetworks ) );
		this.setVirtualNetworksTablesPanelsTabbedPane( this.virtualNetworksTablesPanelsTabbedPane( virtualNetworksNetworks ) );
		this.setVirtualNetworksTablePanel( this.virtualNetworksTablePanel( virtualNetworksNetworks ) );
		
		JTabbedPane virtualNetworksTabbedPane = new JTabbedPane();
		virtualNetworksTabbedPane.setName( "virtualNetworksTabbedPane" );
		virtualNetworksTabbedPane.setTabPlacement( SwingConstants.TOP );
		virtualNetworksTabbedPane.addTab( "Graphical", null, this.getVirtualNetworksViewersPanelsTabbedPane(), "Graphical results of virtual networks" );
		virtualNetworksTabbedPane.addTab( "Numerical", null, this.getVirtualNetworksTablesPanelsTabbedPane(), "Numerical results of virtual networks" );
		virtualNetworksTabbedPane.addTab( "Summary", null, this.getVirtualNetworksTablePanel(), "Summary results of virtual networks" );
		virtualNetworksTabbedPane.addChangeListener( this );
		
		return virtualNetworksTabbedPane;
	}
	private JTabbedPane virtualNetworksVisualizationViewersPanelsTabbedPane( List< List< VirtualNetwork > > virtualNetworksNetworks )
	{	
		this.setVirtualNetworksViewersPanels( new ArrayList< VirtualNetworkViewersPanel >() );
		
		JTabbedPane virtualNetworksVisualizationViewersPanelsTabbedPane = new JTabbedPane();
		
		for( int i = 0; i < virtualNetworksNetworks.size(); i++ )
		{
			String virtualNetworkName = virtualNetworksNetworks.get( i ).get( 0 ).getName();
			List< VirtualNetwork > virtualNetworkNetworks = virtualNetworksNetworks.get( i );
			VirtualNetworkViewersPanel virtualNetworkVisualizationViewersPanel = new VirtualNetworkViewersPanel( virtualNetworkNetworks, this );
			virtualNetworksVisualizationViewersPanelsTabbedPane.addTab( virtualNetworkName, null, virtualNetworkVisualizationViewersPanel, null );
			
			this.getVirtualNetworksViewersPanels().add( virtualNetworkVisualizationViewersPanel );
		}
		
		return virtualNetworksVisualizationViewersPanelsTabbedPane;
	}
	private JTabbedPane virtualNetworksTablesPanelsTabbedPane( List< List< VirtualNetwork > > virtualNetworksNetworks )
	{
		JTabbedPane virtualNetworksTablesPanelsTabbedPane = new JTabbedPane();
		
		this.setVirtualNetworksTablesPanels( new ArrayList< VirtualNetworkTablesPanel >() );
		
		for( int i = 0; i < virtualNetworksNetworks.size(); i++ )
		{
			List< VirtualNetwork > virtualNetworkNetworks = virtualNetworksNetworks.get( i );
			
			String virtualNetworkName = virtualNetworkNetworks.get( 0 ).getName();
			VirtualNetworkTablesPanel virtualNetworkTablesPanel = new VirtualNetworkTablesPanel( virtualNetworkNetworks, this );
			virtualNetworksTablesPanelsTabbedPane.addTab( virtualNetworkName, null, virtualNetworkTablesPanel, null );
			
			this.getVirtualNetworksTablesPanels().add( virtualNetworkTablesPanel );
		}
		
		return virtualNetworksTablesPanelsTabbedPane;
	}
	private JPanel virtualNetworksTablePanel( List< List< VirtualNetwork > > virtualNetworksNetworks )
	{
		JPanel panel = new JPanel();
		panel.add( new JScrollPane( new VirtualNetworksTable( virtualNetworksNetworks ) ) );
		
		return panel;
	}
	
	@Override
	public void stateChanged( ChangeEvent changeEvent )
	{
		String tabbedPaneName = ( (JTabbedPane) changeEvent.getSource() ).getName();
		int tabbedPaneSelectedIndex = ( (JTabbedPane) changeEvent.getSource() ).getSelectedIndex();
		
		if( tabbedPaneName.equals( this.getSdnNetworksTabbedPane().getName() ) )
		{
			if( tabbedPaneSelectedIndex == 0 )
			{	
				tabbedPaneSelectedIndex = this.getSdnNetworksTablesPanelsTabbedPane().getSelectedIndex();
				this.getSdnNetworksViewersPanelsTabbedPane().setSelectedIndex( tabbedPaneSelectedIndex );
			}
			else if( tabbedPaneSelectedIndex == 1 )
			{
				tabbedPaneSelectedIndex = this.getSdnNetworksViewersPanelsTabbedPane().getSelectedIndex();
				this.getSdnNetworksTablesPanelsTabbedPane().setSelectedIndex( tabbedPaneSelectedIndex );
			}
		}
		else if( tabbedPaneName.equals( this.getVirtualNetworksTabbedPane().getName() ) )
		{
			if( tabbedPaneSelectedIndex == 0 )
			{	
				tabbedPaneSelectedIndex = this.getVirtualNetworksTablesPanelsTabbedPane().getSelectedIndex();
				this.getVirtualNetworksViewersPanelsTabbedPane().setSelectedIndex( tabbedPaneSelectedIndex );
			}
			else if( tabbedPaneSelectedIndex == 1 )
			{
				tabbedPaneSelectedIndex = this.getVirtualNetworksViewersPanelsTabbedPane().getSelectedIndex();
				this.getVirtualNetworksTablesPanelsTabbedPane().setSelectedIndex( tabbedPaneSelectedIndex );
			}
		}
	}
	
}
